package com.jiezuo.flowable.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.jiezuo.common.exception.BusinessRuntimeException;
import com.jiezuo.common.util.DateTimeUtil;
import com.jiezuo.common.util.StringUtil;
import com.jiezuo.common.vo.PageVo;
import com.jiezuo.flowable.entity.ModelPageQuery;
import com.jiezuo.flowable.service.MyService;
import com.jiezuo.flowable.service.UserModelService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.exceptions.XMLException;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.ui.common.security.SecurityUtils;
import org.flowable.ui.common.service.exception.ConflictingRequestException;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.model.ModelKeyRepresentation;
import org.flowable.ui.modeler.model.ModelRepresentation;
import org.flowable.ui.modeler.repository.ModelRepository;
import org.flowable.ui.modeler.serviceapi.ModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description 模型管理 创建/删除/发布
 * @author 庞留杰
 * @date 2020/9/11 18:01
 * @version V1.0
 **/
@Slf4j
@Service
public class UserModelServiceImpl implements UserModelService {

    @Autowired
    ProcessEngine processEngine;
    @Autowired
    ModelService modelService;
    @Autowired
    ModelRepository modelRepository;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    RepositoryService repositoryService;
    @Autowired
    TaskService taskService;
    @Autowired
    MyService myService;

    /**
     * 功能描述: 新建一个流程模型
     *      参数参考：flowable-ui-modeler-logic-6.5.0.jar->org.flowable.ui.modeler.model.ModelRepresentation
     * @author: 庞留杰
     * @param  modelRepresentation
     *         包含字段：key:模型;Key name:模型名称;description:模型描述信息;modelType:0
     * @exception
     * @date: 2020/9/10 10:25
     */
    @Override
    public ModelRepresentation createModel(ModelRepresentation modelRepresentation) {
        modelRepresentation.setKey(modelRepresentation.getKey().replaceAll(" ", ""));
        ModelKeyRepresentation modelKeyInfo = modelService.validateModelKey(null, modelRepresentation.getModelType(), modelRepresentation.getKey());
        if (modelKeyInfo.isKeyAlreadyExists()) {
            throw new ConflictingRequestException("模型的KEY已经存在: " + modelRepresentation.getKey() + ",不能重复创建");
        }
        String json = modelService.createModelJson(modelRepresentation);
        Model newModel = modelService.createModel(modelRepresentation, json, SecurityUtils.getCurrentUserObject());
        ModelRepresentation model = new ModelRepresentation(newModel);
        return model;
    }

    /**
     * 功能描述: 查询所有流程模型
     * @author: 庞留杰
     * @param pageVo
     * @exception
     * @date: 2020/9/10 10:25
     */
    @Override
    public Page findModelerPage(PageVo pageVo, ModelPageQuery modelPageQuery) {
        int size = pageVo.getPage_size();
        int current = pageVo.getPage_number();
        int fromIndex = (current - 1) * size;// 每页多少条
        int toIndex = current * size;// 每页多少条
        List<Model> modelList = modelRepository.findByModelType(modelPageQuery.getModelType(), modelPageQuery.getSort());
        List<Model> models = Lists.newArrayList();
        // 通过名字过滤
        if (StringUtil.isNotEmpty(modelPageQuery.getName())) {
            models = modelList.stream().filter(it -> it.getName().indexOf(modelPageQuery.getName()) != -1).collect(Collectors.toList());
        } else {
            models = modelList;
        }
        int count = models.size();
        System.out.println("模型总数量：" + count);
        if (toIndex > count) {
            toIndex = count;
        }
        List<Model> records = models.subList(fromIndex, toIndex);
        JSONArray arr = new JSONArray();
        //查询所有用户信息
        List<Map<String, Object>> allUsers = myService.findAllUsers();
        for (Model model : records) {
            JSONObject obj = new JSONObject();
            obj.put("id", model.getId());
            obj.put("name", model.getName());
            obj.put("key", model.getKey());
            obj.put("description", model.getDescription());
            obj.put("created", DateTimeUtil.format(model.getCreated(), DateTimeUtil.DATE_TIME));//创建时间
            obj.put("lastUpdated", DateTimeUtil.format(model.getLastUpdated(), DateTimeUtil.DATE_TIME));//最后更新时间
            //创建人
            Map<String, Object> map1 = allUsers.stream().filter(e -> (e.get("id") + "").equals(model.getCreatedBy())).findAny().orElse(null);
            if (map1 != null) {
                obj.put("createdBy", model.getCreatedBy());//创建人ID
                obj.put("createdByName", map1.get("real_name"));//创建人
            } else {
                obj.put("createdBy", model.getCreatedBy());//创建人ID
                obj.put("createdByName", null);//创建人
            }
            //更新人
            Map<String, Object> map2 = allUsers.stream().filter(e -> (e.get("id") + "").equals(model.getCreatedBy())).findAny().orElse(null);
            if (map2 != null) {
                obj.put("lastUpdatedBy", model.getLastUpdatedBy());//最后更新人ID
                obj.put("lastUpdatedByName", map2.get("real_name"));//最后更新人
            } else {
                obj.put("lastUpdatedBy", model.getLastUpdatedBy());//最后更新人ID
                obj.put("lastUpdatedByName", null);//最后更新人
            }
            obj.put("version", model.getVersion());
            obj.put("modelEditorJson", model.getModelEditorJson());
            obj.put("comment", model.getComment());
            obj.put("modelType", model.getModelType());
            obj.put("tenantId", model.getTenantId());
            arr.add(obj);
        }
        Page page = new Page(current, size, count);
        page.setRecords(arr);
        page.setTotal(count);
        return page;
    }

    @Override
    public List<Model> findModelerList(ModelPageQuery modelPageQuery) {
        List<Model> modelList = modelRepository.findByModelType(modelPageQuery.getModelType(), modelPageQuery.getSort());
        List<Model> models = Lists.newArrayList();
        // 通过名字过滤
        if (StringUtil.isNotEmpty(modelPageQuery.getName())) {
            models = modelList.stream().filter(it -> it.getName().indexOf(modelPageQuery.getName()) != -1).collect(Collectors.toList());
        } else {
            models = modelList;
        }
        int count = models.size();
        System.out.println("模型总数量：" + count);
        JSONArray arr = new JSONArray();
        //查询所有用户信息
        List<Map<String, Object>> allUsers = myService.findAllUsers();
        for (Model model : models) {
            JSONObject obj = new JSONObject();
            obj.put("id", model.getId());
            obj.put("name", model.getName());
            obj.put("key", model.getKey());
            obj.put("description", model.getDescription());
            obj.put("created", DateTimeUtil.format(model.getCreated(), DateTimeUtil.DATE_TIME));//创建时间
            obj.put("lastUpdated", DateTimeUtil.format(model.getLastUpdated(), DateTimeUtil.DATE_TIME));//最后更新时间
            //创建人
            Map<String, Object> map1 = allUsers.stream().filter(e -> (e.get("id") + "").equals(model.getCreatedBy())).findAny().orElse(null);
            if (map1 != null) {
                obj.put("createdBy", model.getCreatedBy());//创建人ID
                obj.put("createdByName", map1.get("real_name"));//创建人
            } else {
                obj.put("createdBy", model.getCreatedBy());//创建人ID
                obj.put("createdByName", null);//创建人
            }
            //更新人
            Map<String, Object> map2 = allUsers.stream().filter(e -> (e.get("id") + "").equals(model.getCreatedBy())).findAny().orElse(null);
            if (map2 != null) {
                obj.put("lastUpdatedBy", model.getLastUpdatedBy());//最后更新人ID
                obj.put("lastUpdatedByName", map2.get("real_name"));//最后更新人
            } else {
                obj.put("lastUpdatedBy", model.getLastUpdatedBy());//最后更新人ID
                obj.put("lastUpdatedByName", null);//最后更新人
            }
            obj.put("version", model.getVersion());
            obj.put("modelEditorJson", model.getModelEditorJson());
            obj.put("comment", model.getComment());
            obj.put("modelType", model.getModelType());
            obj.put("tenantId", model.getTenantId());
            arr.add(obj);
        }
        return models;
    }

    /**
     * 功能描述: 删除流程模型Model
     * @author: 庞留杰
     * @param   id （ModelId）
     * @exception
     * @date: 2020/9/10 10:26
     */
    @Override
    public void deleteModel(String id) {
        modelService.deleteModel(id);
    }

    /**
     * @description 发布流程图
     * @param         modelId: 流程ID
     * @author 庞留杰
     * @date 2020/9/11 17:59
     * @version V1.0
     **/
    @Override
    public void deploy(String modelId) throws Exception {
        //获取模型
        Model modelData = modelService.getModel(modelId);
        byte[] bytes = modelService.getBpmnXML(modelData);
        if (bytes == null) {
            throw new BusinessRuntimeException("模型数据为空，请先设计流程并成功保存，再进行发布。");
        }
        BpmnModel model = modelService.getBpmnModel(modelData);
        if (model.getProcesses().size() == 0) {
            throw new BusinessRuntimeException("数据模型不符要求，请至少设计一条主线流程。");
        }
        byte[] bpmnBytes = modelService.getBpmnXML(modelData);
        //发布流程
        String processName = modelData.getName() + ".bpmn20.xml";
        Deployment deployment = null;
        try {
            deployment = repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addString(processName, new String(bpmnBytes, "UTF-8"))
                    .deploy();
        } catch (FlowableException e) {
            throw new BusinessRuntimeException("绘制流程图异常，请检查后重新发布");
        } catch (XMLException e) {
            throw new BusinessRuntimeException("绘制流程图异常，请检查后重新发布");
        }
        Model model1 = modelService.saveModel(modelData);
        log.info("deploymentId:{}", deployment.getId());
        log.info("deploymentKey:{}", deployment.getKey());
        log.info("model1Id:{}", model1.getId());
        log.info("model1Key:{}", model1.getKey());
    }

}
